package cn.stimd.spring.aop.framework;

import cn.stimd.spring.aop.Advisor;
import cn.stimd.spring.aop.Pointcut;
import cn.stimd.spring.aop.TargetSource;
import cn.stimd.spring.aop.framework.adapter.AdvisorAdapterRegistry;
import cn.stimd.spring.aop.framework.adapter.DefaultAdvisorAdapterRegistry;
import cn.stimd.spring.aop.framework.autoproxy.TargetSourceCreator;
import cn.stimd.spring.aop.target.SingletonTargetSource;
import cn.stimd.spring.beans.BeansException;
import cn.stimd.spring.beans.factory.BeanFactory;
import cn.stimd.spring.beans.factory.BeanFactoryAware;
import cn.stimd.spring.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.aopalliance.aop.Advice;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
    private Log logger = LogFactory.getLog(getClass());
    private BeanFactory beanFactory;
    //Advisor适配器注册器
    private AdvisorAdapterRegistry advisorAdapterRegistry = new DefaultAdvisorAdapterRegistry();
    //代理对象的类型
    private final Map<Object, Class<?>> proxyTypes = new ConcurrentHashMap<>(16);
    //缓存是否增强Bean，value为false表示不需要增强
    private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
    //缓存提前创建的代理对象，用于解决依赖循环的问题
    private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
    private TargetSourceCreator[] customTargetSourceCreators;
    private final Set<String> targetSourcedBeans = Collections.newSetFromMap(new ConcurrentHashMap<>(16));


    /**
     * 在对象实例化前执行，创建代理
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        //前置检查
        Object cacheKey = StringUtils.hasLength(beanName) ? beanName : beanClass;
        if (!this.targetSourcedBeans.contains(beanName)) {
            if (this.advisedBeans.containsKey(cacheKey)) {
                return null;
            }
            if (isInfrastructureClass(beanClass)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return null;
            }
        }

        //使用自定义的TargetSource创建代理
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            this.targetSourcedBeans.add(beanName);
            //获取拦截器链
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            //创建代理对象
            Object proxy = createProxy(beanClass, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            logger.info("[Aop] [自定义TargetSource代理] --> 目标对象: " + beanName);
            return proxy;
        }
        return null;
    }


    private TargetSource getCustomTargetSource(Class<?> beanClass, String beanName) {
        if (this.customTargetSourceCreators != null) {
            for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
                TargetSource ts = tsc.getTargetSource(beanClass, beanName);
                if (ts != null) {
                    return ts;
                }
            }
        }
        return null;
    }


    /**
     * 提前创建代理，解决循环依赖的问题
     */
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = StringUtils.hasLength(beanName) ? beanName : bean.getClass();
        this.earlyProxyReferences.put(cacheKey, bean);
        logger.info("[Aop] [提前暴露代理] --> 目标对象: " + bean.getClass().getSimpleName());
        return wrapIfNecessary(bean, beanName, cacheKey);
    }


    /**
     * 在对象初始化后执行，创建代理
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = StringUtils.hasLength(beanName) ? beanName : bean.getClass();

            //检查是否提前创建代理，确保创建代理的操作只会执行一次
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return null;
    }

    private Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        //1.1 如果目标Bean已经在缓存中，且不需要代理，直接返回
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
        }

        //1.2 如果是AOP相关的组件类，则加入缓存并标记为不处理
        Class<?> beanClass = bean.getClass();
        if (isInfrastructureClass(beanClass)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }

        //2. 获取增强器（模板方法，由子类实现）
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != null) {
            this.advisedBeans.put(cacheKey, Boolean.TRUE);
            // 3. 创建代理对象
            Object proxy = createProxy(bean.getClass(), specificInterceptors, new SingletonTargetSource(bean));
            this.proxyTypes.put(cacheKey, proxy.getClass());

            logger.info("[Aop] [创建代理对象] --> 目标对象: " + bean.getClass().getSimpleName());
            return proxy;
        }

        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }


    //创建代理对象
    protected Object createProxy(Class<?> beanClass, Object[] specificInterceptors, TargetSource targetSource) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.copyFrom(this);    //将AopConfig复制一份给代理对象

        //判断目标对象使用JDK代理还是Cglib代理
        if (!proxyFactory.isProxyTargetClass()) {
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }

        //将各种Advice转换为统一的Advisor
        Advisor[] advisors = buildAdvisors(specificInterceptors);
        for (Advisor advisor : advisors) {
            proxyFactory.addAdvisor(advisor);
        }
        proxyFactory.setTargetSource(targetSource);
        return proxyFactory.getProxy(); //使用代理工厂创建代理
    }


    protected Advisor[] buildAdvisors(Object[] interceptors) {
        //将各种Advice包装成统一的Advisor，对于DefaultAdvisorAdapterRegistry而言，
        //MethodInterceptor、Advice的子类都包装成DefaultPointcutAdvisor
        if (interceptors != null) {
            Advisor[] advisors = new Advisor[interceptors.length];
            for (int i = 0; i < interceptors.length; i++) {
                advisors[i] = this.advisorAdapterRegistry.wrap(interceptors[i]);
            }
            return advisors;
        }
        return new Advisor[0];
    }


    //跳过与AOP相关的组件类
    protected boolean isInfrastructureClass(Class<?> beanClass) {
        return (Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass)
                || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass));
    }


    /**
     * 增强器有多种类型，具体创建哪种类型需由子类来决定
     */
    protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource customTargetSource);


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    @Override
    public void postProcessPropertyValues(Object bean, String beanName) { }

    public void setCustomTargetSourceCreators(TargetSourceCreator... targetSourceCreators) {
        this.customTargetSourceCreators = targetSourceCreators;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    protected BeanFactory getBeanFactory() {
        return beanFactory;
    }
}
